import { Object3D, PointLight, Texture, TextureLoader, Vector3 } from "three";
import Const from "../../application/constants/Const";
import { Point } from "../../Docs";
import { Tween } from "../../utils/Tween";
import { Lensflare, LensflareElement } from "three/examples/jsm/Addons";
/**
 * 物体漫游。 使用该功能前，需要设置模型的朝向。比如一个飞机模型的机头指向(0,0,1)方向，那么在漫游前，需要将飞机模型的up属性设置为(0,0,1)
 * @example 
 *  let objWander = new GE.ObjWander(model); //模型漫游的功能，该功能对模型的朝向有要求：模型的正面需要Z轴朝上

    var firstPosition =  new GE.Point(120.175646, 30.28362, 10, '4326');
    var secondPosition = new GE.Point(120.175646, 30.28662, 10, '4326');
    var thirdPosition =  new GE.Point(120.175346, 30.28662, 10, '4326');
    var fourPosition =   new GE.Point(120.175346, 30.28362, 10, '4326');

    let path = new Array();//漫游的路径
    path.push({ objPosition: firstPosition });
    path.push({ objPosition: secondPosition });
    path.push({ objPosition: thirdPosition });
    path.push({ objPosition: fourPosition });

    let wanderTime = 10000; //漫游的时间，单位毫秒
    objWander.wander(path, wanderTime, function () { //漫游结束的回调事件
        console.log('the wander is over');
    })
 */
export default class ObjWander {
    private wanderPath: Array<{ objPosition: Point | Vector3, flyTime: number }>; // 漫游路径数据
    private objWandered: Object3D; //漫游的物体
    private onMoveCallback;
    private tween: Tween;

    public constructor(objWandered: Object3D, flickerImg?: string) {
        this.objWandered = objWandered;

        if (flickerImg) {
            this.addLensflare(flickerImg);
        }

    }

    /**
     * 物体从当前位置跳转到指定位置
     * @param endPosition 要跳转到的新位置
     * @param time 跳转时间，0为瞬间跳转，默认2000
     * @example  let cameraPosition = new GE.Point(119, 30, 1000, '4326').toEPSGWeb();
        let lookAtPosition = new GE.Point(119, 30, 0, '4326').toEPSGWeb();
        app.camera.flyTo(cameraPosition, lookAtPosition, 100);
     */
    public flyTo(endPosition: Point | Vector3, time: number = 2000, onCompleteCallback?) {
        let startPosition = this.objWandered.position.clone();

        //@ts-ignore
        this.fly(startPosition, endPosition, time, onCompleteCallback);
    }

    /**
     * 物体从某个位置(非当前视角)跳转到另一个位置
     * @param startPosition 起始位置
     * @param endPosition 终止位置
     * @param time 跳转时间啊，0为瞬间跳转，默认2000
     */
    public fly(startPosition: Point | Vector3, endPosition: Point | Vector3, time: number = 2000, onCompleteCallback?) {
        //调整飞行结束时模型的位置
        if (startPosition instanceof Point) startPosition = startPosition.toEPSGWeb();;
        if (endPosition instanceof Point) endPosition = endPosition.toEPSGWeb();;

        this.objWandered.lookAt(endPosition);

        let start = {
            ex: startPosition.x,
            ey: startPosition.y,
            ez: startPosition.z,
        }
        let end = {
            ex: endPosition.x,
            ey: endPosition.y,
            ez: endPosition.z,
        }
        let self = this;
        this.tween = new Tween(start).to(end, time)
            .onUpdate(() => {
                let curPosition = new Vector3(start.ex, start.ey, start.ez);
                self.objWandered.position.copy(curPosition);

                if (self.onMoveCallback) {
                    self.onMoveCallback();
                }
            }).onComplete(() => {
                self.tween.stop();
                self.tween = null;

                if (self.onMoveCallback) {
                    self.onMoveCallback();
                }

                if (onCompleteCallback) {
                    onCompleteCallback();
                }
            });
        this.tween.start();
    }

    /**
     * 模型漫游
     * @param path 模型漫游的路径，该路径是一个由多个点组成的数组
     * @param path.objPosition 漫游路径上模型的一个位置
     * @param time 漫游的时间，单位毫秒
     * @param onCompleteCallback 漫游结束后的回调函数
     */
    public wander(path: Array<{ objPosition: Point | Vector3 }>, time: number, onFinishCallback?, onMoveCallback?) {
        if (path.length == 0) {
            return;
        }
        this.onMoveCallback = onMoveCallback;
        this.wanderPath = new Array<{ objPosition: Point, flyTime: number }>(); // 重置漫游路径

        let firstPoint = path[0];
        //如果起点不是当前模型的位置, 就把模型位置添加到数组头部
        if (firstPoint.objPosition.x != this.objWandered.position.x || firstPoint.objPosition.y != this.objWandered.position.y || firstPoint.objPosition.z != this.objWandered.position.z) {
            //往path数组的最前面添加一个点
            path.unshift({
                objPosition: this.objWandered.position.clone(),
            });
        }

        //计算path数组中所有点之间的距离之和
        let totalDistance = 0;
        for (let i = 0; i < path.length - 1; i++) {
            let currentPoint = path[i];
            if (currentPoint.objPosition instanceof Point) {
                currentPoint.objPosition.toEPSGWeb();;
            }
            let nextPoint = path[i + 1];
            if (nextPoint.objPosition instanceof Point) {
                nextPoint.objPosition.toEPSGWeb();;
            }

            let distance = currentPoint.objPosition.distanceTo(nextPoint.objPosition);
            totalDistance += distance;
        }

        //计算每两个点之间距离和总距离之间的百分比, 然后计算出每两个点之间需要飞行的时间
        for (let i = 1; i < path.length; i++) {
            let prreviousPoint = path[i - 1];
            let currentPoint = path[i];
            let distance = prreviousPoint.objPosition.distanceTo(currentPoint.objPosition);
            let ratio = distance / totalDistance;
            let flyTime = ratio * time;

            this.wanderPath.push({
                objPosition: currentPoint.objPosition.clone(),
                flyTime: flyTime
            })
        }

        let nextTarget = this.wanderPath.shift();
        this.flyTo(nextTarget.objPosition, nextTarget.flyTime, this.wanderCallback.bind(this, onFinishCallback));
    }

    private wanderCallback(onFinishCallback?) { //漫游的回调
        if (this.wanderPath.length == 0) { //漫游结束
            if (onFinishCallback) {
                onFinishCallback();
            }

            return;
        }
        let nextTarget = this.wanderPath.shift();
        this.flyTo(nextTarget.objPosition, nextTarget.flyTime, this.wanderCallback.bind(this, onFinishCallback));
    }

    private light: PointLight;
    private textureFlare: Texture;
    private lensflare: Lensflare;
    private intervalID;
    private addLensflare(flickerImg) {
        this.light = new PointLight('#E1FFFF', 1, 0);
        this.objWandered.add(this.light);
        const textureLoader = new TextureLoader();

        this.textureFlare = textureLoader.load(flickerImg);
        this.lensflare = new Lensflare();
        this.lensflare.addElement(new LensflareElement(this.textureFlare, 30, 0, this.light.color));
        this.light.add(this.lensflare);

        var countIndex = 0;
        var self = this;
        this.intervalID = setInterval(function () {
            if (countIndex % 2 == 0) {
                countIndex++;
                self.light.color.set('#FF0000');
            } else {
                countIndex = 0;
                self.light.color.set('#E1FFFF');
            }
        }, 500);
    }

    public dispose() {
        clearInterval(this.intervalID);

        this.objWandered.remove(this.light); 
        this.light.dispose();
        this.light = null;

        this.textureFlare.dispose();
        this.textureFlare = null;

        this.lensflare.dispose();
        this.lensflare = null;
    }
}